use std::collections::HashMap;

use honeybee::mongodb::{
    bson::{self, doc, Document},
    options::FindOneOptions,
};
use honeybee::Result;
use serde::{Deserialize, Serialize};

use super::collections;

#[derive(Serialize, Deserialize, Debug, Default)]
pub struct Role {
    pub account: String,
    pub uid: i64,
    pub create_time: i64,
    pub gmsg: HashMap<String, i64>,
    pub test_data: u32,
}

#[allow(dead_code)]
async fn get_by_uid(uid: i64) -> Result<Option<Role>> {
    let coll = collections::role();

    let option = FindOneOptions::builder()
        .projection(Some(doc! {"_id": false}))
        .build();

    coll.find_one(doc! {"uid": uid}, option)
        .await
        .map(|doc| doc.and_then(|doc| bson::from_document(doc).ok()))
        .map_err(|err| err.into())
}

async fn create(account: &str, uid: i64) -> Result<Role> {
    let coll = collections::role();

    let role = Role {
        account: account.to_string(),
        uid,
        create_time: chrono::Local::now().timestamp(),
        ..Default::default()
    };

    let doc = bson::to_document(&role)?;
    coll.insert_one(doc, None).await?;

    Ok(role)
}

pub async fn load_or_create(account: &str, uid: i64) -> Result<Role> {
    let role = get_by_uid(uid).await?;
    if let Some(role) = role {
        return Ok(role);
    }
    let role = create(account, uid).await?;
    Ok(role)
}

pub async fn update(uid: i64, doc: Document) -> Result<()> {
    let coll = collections::role();

    coll.replace_one(doc! {"uid": uid}, doc, None).await?;
    debug!("save role:{}", uid);
    Ok(())
}
